package com.spring.boot.core.coder.writers;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.PrintWriter;
import java.util.Date;

import com.spring.boot.core.coder.parsers.ProtoFileParser;
import com.spring.boot.core.coder.parsers.ProtoFileParser.Field;
import com.spring.boot.core.coder.parsers.ProtoFileParser.Message;
import com.spring.boot.core.coder.parsers.ProtoFileParser.ProtoFile;
import com.spring.boot.core.utils.DateUtil;
import com.spring.boot.core.utils.FileUtils;
import com.spring.boot.core.utils.LinuxUtils;

public class ProtoToClientCode {

	private static void writeMessage_H(PrintWriter writer_h, Message message) {
		writer_h.println(String.format("////////////////////////////////////////////////////////////////////"));
		writer_h.println(String.format("/******************************************************************"));
		writer_h.println(String.format(" * %s", message.name));
		writer_h.println(String.format(" ******************************************************************/"));
		writer_h.println(String.format("////////////////////////////////////////////////////////////////////"));
		writer_h.println(String.format(""));
		writer_h.println(String.format("class %s : public JSONObject {", message.name));
		writer_h.println(String.format("public:"));
		writer_h.println(String.format("    JCREATE_FUNC(%s);", message.name));
		writer_h.println(String.format("    JPARSEJ_FUNC(%s);", message.name));
		writer_h.println(String.format("    JPARSES_FUNC(%s);", message.name));
		writer_h.println(String.format("    JTYPE_FUNC(\"%s\");", message.name));
		writer_h.println(String.format("    JBUILD_FUNC(%s);", message.name));
		writer_h.println(String.format("    JDEFAULT_FUNC(%s);", message.name));
		writer_h.println(String.format(""));
		writer_h.println(String.format("    void decode(const Json::Value& root);"));
		writer_h.println(String.format("    void encode(Json::Value& root);"));
		writer_h.println(String.format(""));
		writer_h.println(String.format("private:"));
		writer_h.println(String.format("    %s();", message.name));
		writer_h.println(String.format("    ~%s();", message.name));
		writer_h.println(String.format(""));
		writer_h.println(String.format("public:"));
		for (Field field : message.fields) {
			writeFieldFunc_H(writer_h, field);
			writer_h.println(String.format(""));
		}
		writer_h.println(String.format("private:"));
		for (Field field : message.fields) {
			writeFieldDef_H(writer_h, field);
		}
		writer_h.println(String.format("};"));
		writer_h.println(String.format(""));
	}

	private static void writeFieldFunc_H(PrintWriter writer_h, Field field) {
		if (field.isArray() == false) {
			if (field.isBool()) {
				writer_h.println(String.format("    JGET_BOOL(%s);", field.full_name));
				writer_h.println(String.format("    JSET_BOOL(%s);", field.full_name));
				writer_h.println(String.format("    JHAS_BOOL(%s);", field.full_name));
				writer_h.println(String.format("    JCLR_BOOL(%s);", field.full_name));
			} else if (field.isInt()) {
				writer_h.println(String.format("    JGET_INT32(%s);", field.full_name));
				writer_h.println(String.format("    JSET_INT32(%s);", field.full_name));
				writer_h.println(String.format("    JHAS_INT32(%s);", field.full_name));
				writer_h.println(String.format("    JCLR_INT32(%s);", field.full_name));
			} else if (field.isLong()) {
				writer_h.println(String.format("    JGET_INT64(%s);", field.full_name));
				writer_h.println(String.format("    JSET_INT64(%s);", field.full_name));
				writer_h.println(String.format("    JHAS_INT64(%s);", field.full_name));
				writer_h.println(String.format("    JCLR_INT64(%s);", field.full_name));
			} else if (field.isFloat()) {
				writer_h.println(String.format("    JGET_FLOAT(%s);", field.full_name));
				writer_h.println(String.format("    JSET_FLOAT(%s);", field.full_name));
				writer_h.println(String.format("    JHAS_FLOAT(%s);", field.full_name));
				writer_h.println(String.format("    JCLR_FLOAT(%s);", field.full_name));
			} else if (field.isDouble()) {
				writer_h.println(String.format("    JGET_DOUBLE(%s);", field.full_name));
				writer_h.println(String.format("    JSET_DOUBLE(%s);", field.full_name));
				writer_h.println(String.format("    JHAS_DOUBLE(%s);", field.full_name));
				writer_h.println(String.format("    JCLR_DOUBLE(%s);", field.full_name));
			} else if (field.isString()) {
				writer_h.println(String.format("    JGET_STRING(%s);", field.full_name));
				writer_h.println(String.format("    JSET_STRING(%s);", field.full_name));
				writer_h.println(String.format("    JHAS_STRING(%s);", field.full_name));
				writer_h.println(String.format("    JCLR_STRING(%s);", field.full_name));
			} else {
				writer_h.println(String.format("    JGET_OBJECT(%s, %s);", field.base_type, field.full_name));
				writer_h.println(String.format("    JSET_OBJECT(%s, %s);", field.base_type, field.full_name));
				writer_h.println(String.format("    JHAS_OBJECT(%s);", field.full_name));
				writer_h.println(String.format("    JCLR_OBJECT(%s);", field.full_name));
			}
		} else {
			if (field.isBool()) {
				writer_h.println(String.format("    JNUM_ARR_BOOL(%s);", field.full_name));
				writer_h.println(String.format("    JALL_ARR_BOOL(%s);", field.full_name));
				writer_h.println(String.format("    JGET_ARR_BOOL(%s);", field.full_name));
				writer_h.println(String.format("    JADD_ARR_BOOL(%s);", field.full_name));
				writer_h.println(String.format("    JSET_ARR_BOOL(%s);", field.full_name));
				writer_h.println(String.format("    JSWP_ARR_BOOL(%s);", field.full_name));
				writer_h.println(String.format("    JDEL_ARR_BOOL(%s);", field.full_name));
				writer_h.println(String.format("    JCLR_ARR_BOOL(%s);", field.full_name));
			} else if (field.isInt()) {
				writer_h.println(String.format("    JNUM_ARR_INT32(%s);", field.full_name));
				writer_h.println(String.format("    JALL_ARR_INT32(%s);", field.full_name));
				writer_h.println(String.format("    JGET_ARR_INT32(%s);", field.full_name));
				writer_h.println(String.format("    JADD_ARR_INT32(%s);", field.full_name));
				writer_h.println(String.format("    JSET_ARR_INT32(%s);", field.full_name));
				writer_h.println(String.format("    JSWP_ARR_INT32(%s);", field.full_name));
				writer_h.println(String.format("    JDEL_ARR_INT32(%s);", field.full_name));
				writer_h.println(String.format("    JCLR_ARR_INT32(%s);", field.full_name));
			} else if (field.isLong()) {
				writer_h.println(String.format("    JNUM_ARR_INT64(%s);", field.full_name));
				writer_h.println(String.format("    JALL_ARR_INT64(%s);", field.full_name));
				writer_h.println(String.format("    JGET_ARR_INT64(%s);", field.full_name));
				writer_h.println(String.format("    JADD_ARR_INT64(%s);", field.full_name));
				writer_h.println(String.format("    JSET_ARR_INT64(%s);", field.full_name));
				writer_h.println(String.format("    JSWP_ARR_INT64(%s);", field.full_name));
				writer_h.println(String.format("    JDEL_ARR_INT64(%s);", field.full_name));
				writer_h.println(String.format("    JCLR_ARR_INT64(%s);", field.full_name));
			} else if (field.isFloat()) {
				writer_h.println(String.format("    JNUM_ARR_FLOAT(%s);", field.full_name));
				writer_h.println(String.format("    JALL_ARR_FLOAT(%s);", field.full_name));
				writer_h.println(String.format("    JGET_ARR_FLOAT(%s);", field.full_name));
				writer_h.println(String.format("    JADD_ARR_FLOAT(%s);", field.full_name));
				writer_h.println(String.format("    JSET_ARR_FLOAT(%s);", field.full_name));
				writer_h.println(String.format("    JSWP_ARR_FLOAT(%s);", field.full_name));
				writer_h.println(String.format("    JDEL_ARR_FLOAT(%s);", field.full_name));
				writer_h.println(String.format("    JCLR_ARR_FLOAT(%s);", field.full_name));
			} else if (field.isDouble()) {
				writer_h.println(String.format("    JNUM_ARR_DOUBLE(%s);", field.full_name));
				writer_h.println(String.format("    JALL_ARR_DOUBLE(%s);", field.full_name));
				writer_h.println(String.format("    JGET_ARR_DOUBLE(%s);", field.full_name));
				writer_h.println(String.format("    JADD_ARR_DOUBLE(%s);", field.full_name));
				writer_h.println(String.format("    JSET_ARR_DOUBLE(%s);", field.full_name));
				writer_h.println(String.format("    JSWP_ARR_DOUBLE(%s);", field.full_name));
				writer_h.println(String.format("    JDEL_ARR_DOUBLE(%s);", field.full_name));
				writer_h.println(String.format("    JCLR_ARR_DOUBLE(%s);", field.full_name));
			} else if (field.isString()) {
				writer_h.println(String.format("    JNUM_ARR_STRING(%s);", field.full_name));
				writer_h.println(String.format("    JALL_ARR_STRING(%s);", field.full_name));
				writer_h.println(String.format("    JGET_ARR_STRING(%s);", field.full_name));
				writer_h.println(String.format("    JADD_ARR_STRING(%s);", field.full_name));
				writer_h.println(String.format("    JSET_ARR_STRING(%s);", field.full_name));
				writer_h.println(String.format("    JSWP_ARR_STRING(%s);", field.full_name));
				writer_h.println(String.format("    JDEL_ARR_STRING(%s);", field.full_name));
				writer_h.println(String.format("    JCLR_ARR_STRING(%s);", field.full_name));
			} else {
				writer_h.println(String.format("    JNUM_ARR_OBJECT(%s);", field.full_name));
				writer_h.println(String.format("    JALL_ARR_OBJECT(%s);", field.full_name));
				writer_h.println(String.format("    JGET_ARR_OBJECT(%s, %s);", field.base_type, field.full_name));
				writer_h.println(String.format("    JADD_ARR_OBJECT(%s, %s);", field.base_type, field.full_name));
				writer_h.println(String.format("    JSET_ARR_OBJECT(%s, %s);", field.base_type, field.full_name));
				writer_h.println(String.format("    JSWP_ARR_OBJECT(%s);", field.full_name));
				writer_h.println(String.format("    JDEL_ARR_OBJECT(%s);", field.full_name));
				writer_h.println(String.format("    JCLR_ARR_OBJECT(%s);", field.full_name));
			}
		}
	}

	private static void writeFieldDef_H(PrintWriter writer_h, Field field) {
		if (field.isArray() == false) {
			if (field.isBool()) {
				writer_h.println(String.format("    JDEF_BOOL(%s);\t%s", field.full_name, field.comment));
			} else if (field.isInt()) {
				writer_h.println(String.format("    JDEF_INT32(%s);\t%s", field.full_name, field.comment));
			} else if (field.isLong()) {
				writer_h.println(String.format("    JDEF_INT64(%s);\t%s", field.full_name, field.comment));
			} else if (field.isFloat()) {
				writer_h.println(String.format("    JDEF_FLOAT(%s);\t%s", field.full_name, field.comment));
			} else if (field.isDouble()) {
				writer_h.println(String.format("    JDEF_DOUBLE(%s);\t%s", field.full_name, field.comment));
			} else if (field.isString()) {
				writer_h.println(String.format("    JDEF_STRING(%s);\t%s", field.full_name, field.comment));
			} else {
				writer_h.println(
						String.format("    JDEF_OBJECT(%s, %s);\t%s", field.base_type, field.full_name, field.comment));
			}
		} else {
			if (field.isBool()) {
				writer_h.println(String.format("    JDEF_ARR_BOOL(%s);\t%s", field.full_name, field.comment));
			} else if (field.isInt()) {
				writer_h.println(String.format("    JDEF_ARR_INT32(%s);\t%s", field.full_name, field.comment));
			} else if (field.isLong()) {
				writer_h.println(String.format("    JDEF_ARR_INT64(%s);\t%s", field.full_name, field.comment));
			} else if (field.isFloat()) {
				writer_h.println(String.format("    JDEF_ARR_FLOAT(%s);\t%s", field.full_name, field.comment));
			} else if (field.isDouble()) {
				writer_h.println(String.format("    JDEF_ARR_DOUBLE(%s);\t%s", field.full_name, field.comment));
			} else if (field.isString()) {
				writer_h.println(String.format("    JDEF_ARR_STRING(%s);\t%s", field.full_name, field.comment));
			} else {
				writer_h.println(String.format("    JDEF_ARR_OBJECT(%s);\t%s", field.full_name, field.comment));
			}
		}
	}

	// write c
	private static void writeMessage_C(PrintWriter writer_c, Message message) {
		writer_c.println(String.format("%s::%s()", message.name, message.name));
		writer_c.println(String.format("{"));
		for (Field field : message.fields) {
			writeFieldAlloc_C(writer_c, field);
		}
		writer_c.println(String.format("}"));
		writer_c.println(String.format(""));

		writer_c.println(String.format("%s::~%s()", message.name, message.name));
		writer_c.println(String.format("{"));
		for (Field field : message.fields) {
			writeFieldFree_C(writer_c, field);
		}
		writer_c.println(String.format("}"));
		writer_c.println(String.format(""));

		writer_c.println(String.format("void %s::decode(const Json::Value& root)", message.name));
		writer_c.println(String.format("{"));
		for (Field field : message.fields) {
			writeFieldDecode_C(writer_c, field);
		}
		writer_c.println(String.format("}"));
		writer_c.println(String.format(""));

		writer_c.println(String.format("void %s::encode(Json::Value& root)", message.name));
		writer_c.println(String.format("{"));
		for (Field field : message.fields) {
			writeFieldEncode_C(writer_c, field);
		}
		writer_c.println(String.format("}"));
		writer_c.println(String.format(""));
	}

	private static void writeFieldAlloc_C(PrintWriter writer_c, Field field) {
		if (field.isArray() == false) {
			if (field.isBool()) {
				writer_c.println(String.format("    JALLOC_BOOL(%s);", field.full_name));
			} else if (field.isInt()) {
				writer_c.println(String.format("    JALLOC_INT32(%s);", field.full_name));
			} else if (field.isLong()) {
				writer_c.println(String.format("    JALLOC_INT64(%s);", field.full_name));
			} else if (field.isFloat()) {
				writer_c.println(String.format("    JALLOC_FLOAT(%s);", field.full_name));
			} else if (field.isDouble()) {
				writer_c.println(String.format("    JALLOC_DOUBLE(%s);", field.full_name));
			} else if (field.isString()) {
				writer_c.println(String.format("    JALLOC_STRING(%s);", field.full_name));
			} else {
				writer_c.println(String.format("    JALLOC_OBJECT(%s);", field.full_name));
			}
		} else {
			if (field.isBool()) {
				writer_c.println(String.format("    JALLOC_ARR_BOOL(%s);", field.full_name));
			} else if (field.isInt()) {
				writer_c.println(String.format("    JALLOC_ARR_INT32(%s);", field.full_name));
			} else if (field.isLong()) {
				writer_c.println(String.format("    JALLOC_ARR_INT64(%s);", field.full_name));
			} else if (field.isFloat()) {
				writer_c.println(String.format("    JALLOC_ARR_FLOAT(%s);", field.full_name));
			} else if (field.isDouble()) {
				writer_c.println(String.format("    JALLOC_ARR_DOUBLE(%s);", field.full_name));
			} else if (field.isString()) {
				writer_c.println(String.format("    JALLOC_ARR_STRING(%s);", field.full_name));
			} else {
				writer_c.println(String.format("    JALLOC_ARR_OBJECT(%s);", field.full_name));
			}
		}
	}

	private static void writeFieldFree_C(PrintWriter writer_c, Field field) {
		if (field.isArray() == false) {
			if (field.isBool()) {
				writer_c.println(String.format("    JFREE_BOOL(%s);", field.full_name));
			} else if (field.isInt()) {
				writer_c.println(String.format("    JFREE_INT32(%s);", field.full_name));
			} else if (field.isLong()) {
				writer_c.println(String.format("    JFREE_INT64(%s);", field.full_name));
			} else if (field.isFloat()) {
				writer_c.println(String.format("    JFREE_FLOAT(%s);", field.full_name));
			} else if (field.isDouble()) {
				writer_c.println(String.format("    JFREE_DOUBLE(%s);", field.full_name));
			} else if (field.isString()) {
				writer_c.println(String.format("    JFREE_STRING(%s);", field.full_name));
			} else {
				writer_c.println(String.format("    JFREE_OBJECT(%s);", field.full_name));
			}
		} else {
			if (field.isBool()) {
				writer_c.println(String.format("    JFREE_ARR_BOOL(%s);", field.full_name));
			} else if (field.isInt()) {
				writer_c.println(String.format("    JFREE_ARR_INT32(%s);", field.full_name));
			} else if (field.isLong()) {
				writer_c.println(String.format("    JFREE_ARR_INT64(%s);", field.full_name));
			} else if (field.isFloat()) {
				writer_c.println(String.format("    JFREE_ARR_FLOAT(%s);", field.full_name));
			} else if (field.isDouble()) {
				writer_c.println(String.format("    JFREE_ARR_DOUBLE(%s);", field.full_name));
			} else if (field.isString()) {
				writer_c.println(String.format("    JFREE_ARR_STRING(%s);", field.full_name));
			} else {
				writer_c.println(String.format("    JFREE_ARR_OBJECT(%s);", field.full_name));
			}
		}
	}

	private static void writeFieldEncode_C(PrintWriter writer_c, Field field) {
		if (field.isArray() == false) {
			if (field.isBool()) {
				writer_c.println(String.format("    JENCODE_BOOL(root, %s, \"%s\");", field.full_name, field.name));
			} else if (field.isInt()) {
				writer_c.println(String.format("    JENCODE_INT32(root, %s, \"%s\");", field.full_name, field.name));
			} else if (field.isLong()) {
				writer_c.println(String.format("    JENCODE_INT64(root, %s, \"%s\");", field.full_name, field.name));
			} else if (field.isFloat()) {
				writer_c.println(String.format("    JENCODE_FLOAT(root, %s, \"%s\");", field.full_name, field.name));
			} else if (field.isDouble()) {
				writer_c.println(String.format("    JENCODE_DOUBLE(root, %s, \"%s\");", field.full_name, field.name));
			} else if (field.isString()) {
				writer_c.println(String.format("    JENCODE_STRING(root, %s, \"%s\");", field.full_name, field.name));
			} else {
				writer_c.println(String.format("    JENCODE_OBJECT(root, %s, \"%s\");", field.full_name, field.name));
			}
		} else {
			if (field.isBool()) {
				writer_c.println(String.format("    JENCODE_ARR_BOOL(root, %s, \"%s\");", field.full_name, field.name));
			} else if (field.isInt()) {
				writer_c.println(
						String.format("    JENCODE_ARR_INT32(root, %s, \"%s\");", field.full_name, field.name));
			} else if (field.isLong()) {
				writer_c.println(
						String.format("    JENCODE_ARR_INT64(root, %s, \"%s\");", field.full_name, field.name));
			} else if (field.isFloat()) {
				writer_c.println(
						String.format("    JENCODE_ARR_FLOAT(root, %s, \"%s\");", field.full_name, field.name));
			} else if (field.isDouble()) {
				writer_c.println(
						String.format("    JENCODE_ARR_DOUBLE(root, %s, \"%s\");", field.full_name, field.name));
			} else if (field.isString()) {
				writer_c.println(
						String.format("    JENCODE_ARR_STRING(root, %s, \"%s\");", field.full_name, field.name));
			} else {
				writer_c.println(
						String.format("    JENCODE_ARR_OBJECT(root, %s, \"%s\");", field.full_name, field.name));
			}
		}
	}

	private static void writeFieldDecode_C(PrintWriter writer_c, Field field) {
		if (field.isArray() == false) {
			if (field.isBool()) {
				writer_c.println(String.format("    JDECODE_BOOL(root, %s, \"%s\");", field.full_name, field.name));
			} else if (field.isInt()) {
				writer_c.println(String.format("    JDECODE_INT32(root, %s, \"%s\");", field.full_name, field.name));
			} else if (field.isLong()) {
				writer_c.println(String.format("    JDECODE_INT64(root, %s, \"%s\");", field.full_name, field.name));
			} else if (field.isFloat()) {
				writer_c.println(String.format("    JDECODE_FLOAT(root, %s, \"%s\");", field.full_name, field.name));
			} else if (field.isDouble()) {
				writer_c.println(String.format("    JDECODE_DOUBLE(root, %s, \"%s\");", field.full_name, field.name));
			} else if (field.isString()) {
				writer_c.println(String.format("    JDECODE_STRING(root, %s, \"%s\");", field.full_name, field.name));
			} else {
				writer_c.println(String.format("    JDECODE_OBJECT(root, %s, %s, \"%s\");", field.base_type,
						field.full_name, field.name));
			}
		} else {
			if (field.isBool()) {
				writer_c.println(String.format("    JDECODE_ARR_BOOL(root, %s, \"%s\");", field.full_name, field.name));
			} else if (field.isInt()) {
				writer_c.println(
						String.format("    JDECODE_ARR_INT32(root, %s, \"%s\");", field.full_name, field.name));
			} else if (field.isLong()) {
				writer_c.println(
						String.format("    JDECODE_ARR_INT64(root, %s, \"%s\");", field.full_name, field.name));
			} else if (field.isFloat()) {
				writer_c.println(
						String.format("    JDECODE_ARR_FLOAT(root, %s, \"%s\");", field.full_name, field.name));
			} else if (field.isDouble()) {
				writer_c.println(
						String.format("    JDECODE_ARR_DOUBLE(root, %s, \"%s\");", field.full_name, field.name));
			} else if (field.isString()) {
				writer_c.println(
						String.format("    JDECODE_ARR_STRING(root, %s, \"%s\");", field.full_name, field.name));
			} else {
				writer_c.println(String.format("    JDECODE_ARR_OBJECT(root, %s, %s, \"%s\");", field.base_type,
						field.full_name, field.name));
			}
		}
	}

	public static void writeProtoFile(ProtoFile file, String path, String name) throws Exception {
		PrintWriter writer_h = new PrintWriter(path + name + ".h", "UTF-8");

		writer_h.println(String.format("//"));
		writer_h.println(String.format("//  %s.h [auto generate]", name));
		writer_h.println(String.format("//  leaguem client"));
		writer_h.println(String.format("//"));
		writer_h.println(String.format("//  Created by houge on %s.", DateUtil.defFormatDate(new Date())));
		writer_h.println(String.format("//"));
		writer_h.println(String.format("//"));
		writer_h.println(String.format(""));
		writer_h.println(String.format("#ifndef __leaguem__%s__", name));
		writer_h.println(String.format("#define __leaguem__%s__", name));
		writer_h.println(String.format(""));
		writer_h.println(String.format("#include \"JSONObject.h\""));
		writer_h.println(String.format(""));
		if (file.package_name != null && file.package_name.length() > 0) {
			writer_h.println(String.format("#define NS_%s_BEGIN namespace %s {", file.package_name.toUpperCase(),
					file.package_name));
			writer_h.println(String.format("#define NS_%s_END   }", file.package_name.toUpperCase()));
			writer_h.println(String.format("#define USING_NS_%s  using namespace %s", file.package_name.toUpperCase(),
					file.package_name));
		} else {
			writer_h.println(String.format("#define NS_%s_BEGIN", file.package_name.toUpperCase()));
			writer_h.println(String.format("#define NS_%s_END", file.package_name.toUpperCase()));
			writer_h.println(String.format("#define USING_NS_%s", file.package_name.toUpperCase()));
		}
		writer_h.println(String.format(""));
		writer_h.println(String.format("NS_%s_BEGIN", file.package_name.toUpperCase()));
		writer_h.println(String.format(""));
		// 预定义
		for (Message message : file.messages) {
			if (message.name.startsWith("Proto"))
				continue;
			writer_h.println(String.format("class %s;", message.name));
		}
		writer_h.println(String.format(""));
		// 定义类
		for (Message message : file.messages) {
			if (message.name.startsWith("Proto"))
				continue;
			writeMessage_H(writer_h, message);
		}
		writer_h.println(String.format("NS_%s_END", file.package_name.toUpperCase()));
		writer_h.println(String.format(""));
		writer_h.println(String.format("#endif /* defined(__leaguem__%s__) */", name));

		writer_h.close();

		PrintWriter writer_c = new PrintWriter(path + name + ".cpp", "UTF-8");

		writer_c.println(String.format("//"));
		writer_c.println(String.format("//  %s.cpp [auto generate]", name));
		writer_c.println(String.format("//  leaguem client"));
		writer_c.println(String.format("//"));
		writer_c.println(String.format("//  Created by houge on %s.", DateUtil.defFormatDate(new Date())));
		writer_c.println(String.format("//"));
		writer_c.println(String.format("//"));
		writer_c.println(String.format(""));
		writer_c.println(String.format("#include \"%s.h\"", name));
		writer_c.println(String.format(""));
		writer_c.println(String.format("NS_%s_BEGIN", file.package_name.toUpperCase()));
		writer_c.println(String.format(""));
		// 类实现
		for (Message message : file.messages) {
			if (message.name.startsWith("Proto"))
				continue;
			writeMessage_C(writer_c, message);
		}
		writer_c.println(String.format(""));
		writer_c.println(String.format("NS_%s_END", file.package_name.toUpperCase()));
		writer_c.close();
	}

	public static void copyServerProtoToClient(String server_file, String client_file, String package_name)
			throws Exception {
		PrintWriter writer = new PrintWriter(client_file, "UTF-8");
		BufferedReader reader = new BufferedReader(new FileReader(server_file));

		writer.println(String.format("package %s;", package_name));
		writer.println(String.format(""));
		writer.println(String.format("option optimize_for = LITE_RUNTIME; "));
		writer.println(String.format(""));

		String line;
		while ((line = reader.readLine()) != null) {
			if (line.contains("optimize_for")) {
				continue;
			}
			if (line.contains("option") && line.contains("java")) {
				continue;
			}
			writer.println(line);
		}

		reader.close();
		writer.close();
	}

	public static void writeAtTestResourceDir(String server_file, String out_path, String out_name, String package_name)
			throws Exception {
		String path = FileUtils.getTestResourceDir();
		FileUtils.createDirs(path + out_path);
		String client_file = out_path + out_name + ".proto";
		String server_full_file = FileUtils.getClassDir() + server_file;
		copyServerProtoToClient(server_full_file, path + client_file, package_name);

		writeProtoFile(ProtoFileParser.parse(new File(path + client_file)), path + out_path, out_name);
	
		String relative_path = FileUtils.getRelativeTestResourceDir();
		String command = String.format("/usr/local/bin/protoc --cpp_out=. %s/%s", relative_path, client_file);
		System.out.println(command + " ---> " + LinuxUtils.exec(command));
	}
}
